    #include <iostream>
    #include <string>
    using namespace std;

    // constants for rows and columns of tic-tac-toe board
    const int ROWS = 3;
    const int COLS = 3;

    enum eGameState { TIE = -1, PLAY, WON }; // make things easier to read

    // function headers
    void outputBoard(char board[ROWS][COLS]);
    bool processPlayerInput( string playerName, char player, char board[ROWS][COLS], int* gameState, int numTurnsbool);
    int hasPlayerWon(int userRow, int userColumn, int numTurns, char board[ROWS][COLS]);
    void gameHasEnded(int gameState, string playerName, char player);


    int main()
    {
            cout << "Welcome to JWorld137 Tic-Tac-Toe!" << endl; //Welcome them

            int gameState = PLAY; // flag for game has been won
            int numTurns = 0; // initialize turn counter
            string playerName1; // player1 name
            string playerName2; // player2 name
            char player = 'X'; // player X starts
            char board[ROWS][COLS]; // initialize our tic-tac-toe board

            cout << "Please enter your name (player1)" << endl; //ask for their name
            cin >> playerName1; //they tell us their name

            cout << "Please enter your name(player2)" << endl; //ask for the second player name
            cin >> playerName2; // they tell us their name

            string playerName = playerName1; // set player1 to X

            memset(board, '*', sizeof(board)); // assign * to every element in the array without an ugly array initialization list

            outputBoard(board); // output board initially

            do
            {
                    if ( processPlayerInput( playerName, player, board, &gameState, numTurns) ) // was the last turn valid?
                    {
                        numTurns++; // increment number of turns
                        player = ( player == 'X' ) ? 'O' : 'X'; // swap player after the turn
                        playerName = ( playerName == playerName1 ) ? playerName2 : playerName1; // swap player name after the turn
                    }
                    system("cls"); // redraw screen
                    outputBoard(board); // output updated board
            } while (gameState == PLAY); // repeat while the game hasn't won

            gameHasEnded(gameState, playerName, player); // game is done! handle it
            system("pause"); // wait for user exit (assuming the user did not launch this via "Start without debugging...", they can see the final result)
            return 0; // obligatory return after the game has ended
    }

    void outputBoard(char board[ROWS][COLS])
    {
                    cout << "\n\n\n\n\tCol: 1 2 3" << endl; // label columns
                    cout << "\tRow:" << endl; //create row under it
                    for(int row = 0; row < 3; row++) // output rows
                    {
                            cout << "\t" << (row+1) << "    "; // label rows
                            for(int col = 0; col < 3; col++) // output columns
                                    {
                                            cout << board[row][col] << " "; // output board
                                    }

                            cout << endl << endl; // new line for input line
                    }
    }

    bool processPlayerInput(string playerName, char player, char board[ROWS][COLS], int* gameState, int numTurns)
    {
                    // initialize user row & column selection variables
                    int userRow = 0;
                    int userColumn = 0;

                    // ask user for input and store
                    cout << "\tIt's " << playerName << "(" << player << ")" << "'s turn." << endl;
                    cout << "\tEnter row and column:" << endl << endl;
                    cout << "\tPlease don't put any spaces!" << endl;
                    cout << "\tRow: ";
                    cin >> userRow;
                    cout << "\tColumn: ";
                    cin >> userColumn;
                    userRow--; // decrement by 1 for proper use
                    userColumn--; // decrement by 1 for proper use

                    // check that input is valid (both row and column are between 0 and 2) and that the user isn't trying to overwrite an already played spot on the board
                    if (userRow >= 0 && userRow <= 2 && userColumn >=0 && userColumn <=2 && board[userRow][userColumn] == '*')
                    {
                            board[userRow][userColumn] = player; // fill in user's choice
                            *gameState = hasPlayerWon(userRow, userColumn, numTurns, board); // check if player has won
                            return true; // turn is valid
                    }

                    cout << "Invalid option.\n";
                    system("pause"); // pause program and wait for user acknowledgement, since screen is redrawn after each turn and without this pause, the user wouldn't see the "Invalid option." text
                    return false; // turn is invalid
    }

    int hasPlayerWon(int userRow, int userColumn, int numTurns, char board[ROWS][COLS])
    {
             if (board [0][userColumn] == board [1][userColumn] && board [0][userColumn] == board [2][userColumn]) // check if one columns are equal (check if they are in a row)
            {
                    return WON;
            }
            else if (board [userRow][0] == board [userRow][1] && board[userRow][0] == board [userRow][2]) // check if one row is equal
            {
                    return WON;
            }
            else if (board [0][0] == board [1][1] && board [0][0] == board [2][2] && board [0][0] != '*') // check top left -> bottom right
            {
                    return WON;
            }
            else if (board [0][2] == board [1][1] && board [0][2] == board [2][0] && board [0][2] != '*') // check bottom left -> top right
            {
                    return WON;
            }
            else if (numTurns >= ROWS*COLS - 1) // turns start at 0, end at 8 - check if we have gone 9 turns; if so, there is a tie
            {
                    return TIE;
            }
            return PLAY; // return PLAY in case something breaks
    }

    void gameHasEnded(int gameState, string playerName, char player)
    {
            int asked;
            player = ((player == 'X' ) ? 'O' : 'X'); // swap the player again since processPlayerInput always returns the next player
            switch (gameState)
            {
                    case TIE:
                            cout << "Tie! Thanks for playing, better luck next time." << endl;
                            break;
                    case WON:
                            cout << playerName << "(" << player << ")" << " has won! Congratulations." << endl;
                            break;
            }
            cout << "Would you like to play again?" << endl; // ask them if they want to play again
            cout << "Enter 1 for yes and 0 for no" << endl; //tell them what values to put in to play again
            cin >> asked; //they tell us if they want to play again

            if (asked==1) //check if they want to play again
            {
                main();
            }
    }
